--- /dev/null
+/*
+
+ Support for G7ToWin data files (.g7t),
+ Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
+*/
+
+/*
+ History:
+ 04/07/2007: start programming
+*/
+
+#include "defs.h"
+#include "csv_util.h"
+#include "garmin_fs.h"
+#include "garmin_tables.h"
+#include "jeeps/gpsmath.h"
+#include "strptime.h"
+
+#include <time.h>
+
+#if CSVFMTS_ENABLED
+
+#define MYNAME "g7towin"
+
+#define G7T_HEADER "Version 2:G7T"
+
+static gbfile *fin;
+static grid_type grid;
+static int datum;
+static gpsdata_type mode;
+static double altf;
+static int gardown;
+static int event_ct;
+
+static
+arglist_t g7towin_args[] = {
+ ARG_TERMINATOR
+};
+
+#define WAYPT__OFS 0x00000
+#define TRKPT__OFS 0x01000
+
+#define WPT_c0_OFS 0x0c000
+#define WPT_c1_OFS 0x0c100
+#define WPT_c2_OFS 0x0c200
+#define WPT_c3_OFS 0x0c300
+#define WPT_c4_OFS 0x0c400
+#define WPT_c5_OFS 0x0c500
+#define WPT_c6_OFS 0x0c600
+#define WPT_c7_OFS 0x0c700
+#define WPT_c8_OFS 0x0c800
+#define WPT_cA_OFS 0x0cA00
+#define WPT_cB_OFS 0x0cB00
+#define WPT_cC_OFS 0x0cC00
+#define WPT_cD_OFS 0x0cD00
+
+static void
+parse_line(char *buff, int index, const char *delimiter, waypoint *wpt)
+{
+ char *cin;
+ garmin_fs_p gmsd = GMSD_FIND(wpt);
+
+ while ((cin = csv_lineparse(buff, delimiter, "", index++))) {
+
+ buff = NULL;
+ cin = lrtrim(cin);
+
+ if ((*cin == '\0') ||
+ (strcmp(cin, "INF") == 0) ||
+ (strcmp(cin, "1e25") == 0) ||
+ (strcmp(cin, "1.0e25") == 0)) continue;
+
+ switch(index) {
+
+ int categories, dyn;
+ struct tm tm;
+ char *cerr;
+
+ case TRKPT__OFS + 1:
+ cin += parse_coordinates(cin, datum, grid,
+ &wpt->latitude, &wpt->longitude, MYNAME);
+ while (isspace(*cin)) cin++;
+
+ memset(&tm, 0, sizeof(tm));
+ cerr = strptime(cin, "%a %b %d %H:%M:%S %Y", &tm);
+ if (cerr == NULL) {
+ fatal(MYNAME ": Unable to convert date (%s)!\n", cin);
+ }
+ wpt->creation_time = mkgmtime(&tm);
+ break;
+
+ case WAYPT__OFS + 1:
+ wpt->description = xstrdup(cin);
+ break;
+
+ case WAYPT__OFS + 2:
+ wpt->icon_descr = gt_find_desc_from_icon_number(
+ atoi(cin), PCX, &dyn);
+ wpt->wpt_flags.icon_descr_is_dynamic = dyn;
+ break;
+
+ case WAYPT__OFS + 4:
+ if (strcmp(cin, "S+C") == 0) {
+ GMSD_SET(display, gt_display_mode_symbol_and_comment);
+ }
+ else if (strcmp(cin, "S") == 0) {
+ GMSD_SET(display, gt_display_mode_symbol);
+ }
+ else if (strcmp(cin, "S+N") == 0) {
+ GMSD_SET(display, gt_display_mode_symbol_and_name);
+ }
+ break;
+
+ case WPT_cA_OFS + 1:
+ case WPT_c1_OFS + 1:
+ if (wpt->shortname) xfree(wpt->shortname);
+ wpt->shortname = xstrdup(cin);
+ break;
+
+ case WPT_cA_OFS + 4:
+ case WPT_c4_OFS + 2:
+ GMSD_SETSTR(city, cin);
+ break;
+
+ case WPT_cA_OFS + 5:
+ case WPT_c4_OFS + 3:
+ GMSD_SETSTR(state, cin);
+ break;
+
+ case WPT_cA_OFS + 6:
+ case WPT_c4_OFS + 4:
+ GMSD_SETSTR(cc, cin);
+ break;
+
+ case WPT_cB_OFS + 1:
+ case WPT_c6_OFS + 2:
+ GMSD_SETSTR(facility, cin);
+ break;
+
+ case WPT_cB_OFS + 2:
+ case WPT_c6_OFS + 3:
+ GMSD_SETSTR(addr, cin);
+ break;
+
+ case WPT_cB_OFS + 3: /*cross road */
+ case WPT_c6_OFS + 4:
+ GMSD_SETSTR(cross_road, cin);
+ break;
+
+ case TRKPT__OFS + 2: /* altitude */
+ case WPT_cC_OFS + 1:
+ case WPT_c5_OFS + 1:
+ case WPT_c8_OFS + 1:
+ wpt->altitude = altf * atof(cin);
+ break;
+
+ case TRKPT__OFS + 3: /* depth */
+ case WPT_cC_OFS + 2:
+ case WPT_c5_OFS + 2:
+ case WPT_c8_OFS + 2:
+ GMSD_SET(depth, altf * atof(cin));
+ break;
+
+ case TRKPT__OFS + 10: /* temperature */
+ if (*cin == '|') cin++; /* in track points */
+ if (strcmp(cin, "1e25") == 0) break;
+ if (strcmp(cin, "1.0e25") == 0) break;
+ /* !!! NO BREAK !!! */
+ case WPT_cD_OFS + 1:
+ case WPT_cB_OFS + 6:
+ GMSD_SET(temperature, atof(cin));
+ break;
+
+ case WAYPT__OFS + 6: /* proximity */
+ case WPT_cD_OFS + 2:
+ GMSD_SET(proximity, atof(cin));
+ break;
+
+ case WPT_cB_OFS + 5:
+ case WPT_cD_OFS + 3:
+ categories = atoi(cin);
+ if (categories != 0)
+ GMSD_SET(category, atoi(cin));
+ break;
+
+#if 0
+
+/* currently unused */
+
+ case TRKPT__OFS + 5: /* distance from previous point */
+ case TRKPT__OFS + 6: /* distance from segment start */
+ case TRKPT__OFS + 7: /* distance from start */
+ case TRKPT__OFS + 8: /* velocity from previous point */
+ case TRKPT__OFS + 9: /* time (in seconds) from previous point */
+ break;
+
+ case WAYPT__OFS + 3: /* ignore color */
+ break;
+
+ case WAYPT__OFS + 5: /* always '0' */
+ break;
+
+ case TRKPT__OFS + 4:
+ if (case_ignore_strcmp(cin, "FT") == 0) ;
+ else if (case_ignore_strcmp(cin, "M") == 0) ;
+ else if (case_ignore_strcmp(cin, "SM") == 0) ;
+ else if (case_ignore_strcmp(cin, "NM") == 0) ;
+ else if (case_ignore_strcmp(cin, "KM") == 0) ;
+ break;
+
+ case WPT_cB_OFS + 4: /* unknown (datatype) */
+ break;
+
+ case WPT_cC_OFS + 3: /* waypt_class (always FF) */
+ break;
+
+ case WPT_cC_OFS + 4: /* class & subclass */
+ case WPT_cC_OFS + 5:
+ case WPT_cC_OFS + 6:
+ case WPT_cC_OFS + 7:
+ case WPT_cC_OFS + 8:
+ case WPT_cC_OFS + 9:
+ case WPT_cC_OFS + 10:
+ case WPT_cC_OFS + 11:
+ case WPT_cC_OFS + 12:
+ case WPT_cC_OFS + 13:
+ case WPT_cC_OFS + 14:
+ case WPT_cC_OFS + 15:
+ case WPT_cC_OFS + 16:
+ case WPT_cC_OFS + 17:
+ case WPT_cC_OFS + 18:
+ case WPT_cC_OFS + 19:
+ case WPT_cC_OFS + 20:
+ case WPT_cC_OFS + 21:
+ break;
+
+ case WPT_cC_OFS + 22:
+ /* distance */
+ break;
+#endif
+ }
+ }
+}
+
+static waypoint *
+parse_waypt(char *buff)
+{
+ char *cin, *cerr;
+ int i;
+ struct tm tm;
+ waypoint *wpt;
+ garmin_fs_p gmsd;
+
+ wpt = waypt_new();
+ gmsd = garmin_fs_alloc(-1);
+ fs_chain_add(&wpt->fs, (format_specific_data *) gmsd);
+
+ if (gardown)
+ cin = buff + 6;
+ else
+ cin = buff + 15;
+
+ while (isspace(*cin)) cin--;
+ if (cin >= buff)
+ wpt->shortname = xstrndup(buff, cin - buff + 1);
+
+ if (gardown)
+ buff += 7;
+ else
+ buff += 16;
+
+ buff += parse_coordinates(buff, datum, grid,
+ &wpt->latitude, &wpt->longitude, MYNAME);
+ while (isspace(*buff)) buff++;
+
+ memset(&tm, 0, sizeof(tm));
+ cerr = strptime(buff, "%a %b %d %H:%M:%S %Y", &tm);
+ if (cerr == NULL)
+ fatal(MYNAME ": Unable to convert date (%s)!\n", buff);
+ wpt->creation_time = mkgmtime(&tm);
+
+ /* go over time stamp */
+ i = 5;
+ while (buff && i) {
+ i--;
+ buff = strchr(buff, ' ');
+ if (buff) buff++;
+ }
+ if (gardown && (buff == NULL)) return wpt;
+ is_fatal((buff == NULL), MYNAME ": Incomplete waypoint line!");
+
+ while (isspace(*buff)) buff++;
+
+ parse_line(buff, WAYPT__OFS, "^", wpt);
+
+ return wpt;
+}
+
+static waypoint *
+parse_trkpt(char *buff)
+{
+ garmin_fs_p gmsd;
+ waypoint *wpt;
+
+ wpt = waypt_new();
+ gmsd = garmin_fs_alloc(-1);
+ fs_chain_add(&wpt->fs, (format_specific_data *) gmsd);
+
+ parse_line(buff, TRKPT__OFS, ";", wpt);
+
+ return wpt;
+}
+
+/*
+ * parse_categories is currently only a dummy procedure.
+ * w'll need a central storage with binding to the module
+ * which has established a list of category names.
+ */
+
+static void
+parse_categories(char *buff)
+{
+ char *cin;
+ int cat = 0;
+
+ while ((cin = csv_lineparse(buff, ",", "", cat++))) {
+ gbuint16 cx;
+
+ buff = NULL;
+
+ cin = lrtrim(cin);
+ if (*cin == 0) continue;
+
+ garmin_fs_convert_category(cin, &cx);
+ }
+}
+
+
+/* main functions */
+
+static void
+rd_init(const char *fname)
+{
+ fin = gbfopen(fname, "rb", MYNAME);
+
+ gardown = 1;
+ mode = wptdata;
+ grid = grid_lat_lon_dmm;
+ datum = DATUM_WGS84;
+ altf = 1;
+ event_ct = 0;
+}
+
+static void
+rd_deinit(void)
+{
+ gbfclose(fin);
+}
+
+static void
+data_read(void)
+{
+ char *buff;
+ int line = 0;
+ waypoint *wpt = NULL;
+ waypoint *prev = NULL;
+ route_head *head = NULL;
+
+ while ((buff = gbfgetstr(fin))) {
+ char *cin = buff;
+ char *cdata;
+
+ line++;
+
+ cin = lrtrim(buff);
+ if (!*cin) continue;
+
+ cdata = cin+1;
+ while (! isspace(*cdata)) cdata++;
+ while (isspace(*cdata)) cdata++;
+ if (! *cdata) continue;
+
+ switch(*cin) {
+
+ case '#': /* comment */
+ break;
+
+ case 'A':
+ if (case_ignore_strncmp(cdata, "Meter", 5) == 0)
+ altf = 1.0;
+ else if (case_ignore_strncmp(cdata, "Feet", 4) == 0)
+ altf = FEET_TO_METERS(1.0);
+ break;
+
+ case 'C': /* categories */
+ parse_categories(cdata);
+ break;
+
+ case 'D':
+ datum = gt_lookup_datum_index(cdata, MYNAME);
+ break;
+
+ case 'I': /* event point */
+ wpt = waypt_new();
+ cdata += parse_coordinates(cdata, datum, grid,
+ &wpt->latitude, &wpt->longitude, MYNAME);
+ xasprintf(&wpt->shortname, "Event%d", ++event_ct);
+ while (isspace(*cdata)) cdata++;
+ if (*cdata == ';') {
+ int dyn;
+
+ cdata++;
+ wpt->icon_descr = gt_find_desc_from_icon_number(
+ atoi(cdata), PCX, &dyn);
+ wpt->wpt_flags.icon_descr_is_dynamic = dyn;
+ }
+ waypt_add(wpt);
+ break;
+
+ case 'M':
+ grid = gt_lookup_grid_type(cdata, MYNAME);
+ break;
+
+ case 'P': /* proximity waypoint */
+ case 'W': /* normal waypoint */
+ wpt = parse_waypt(cdata);
+ prev = wpt;
+ if (wpt) {
+ if (mode == rtedata)
+ route_add_wpt(head, wpt);
+ else
+ waypt_add(wpt);
+ }
+ break;
+
+ case 'c': /* additional lines */
+ switch(*(cin+1)) {
+ int index;
+
+ case 'A': case 'B':
+ case 'C': case 'D':
+
+ index = WPT_cA_OFS + ((*(cin+1) - 'A') * 256);
+ parse_line(cdata, index, "|", wpt);
+ break;
+
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8':
+
+ index = WPT_c0_OFS + ((*(cin+1) - '0') * 256);
+ parse_line(cdata, index, ";", wpt);
+ break;
+
+ case 'L':
+ waypt_add_url(wpt, xstrdup(cdata), NULL);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 'N': /* track log header */
+ mode = trkdata;
+ head = route_head_alloc();
+ cdata = strchr(cdata, '-');
+ if (cdata) {
+ while (isspace(*cdata)) cdata++;
+ if (*cdata) {
+ char *s;
+ s = strrchr(cdata, ',');
+ if (s) {
+ *s = '\0';
+ s = strrchr(cdata, ',');
+ if (s) {
+ *s = '\0';
+ head->rte_name = xstrdup(cdata);
+ }
+ }
+ }
+ }
+ track_add_head(head);
+ break;
+
+ case 'R': /* route header */
+ mode = rtedata;
+ head = route_head_alloc();
+ cdata += 3; /*skip route number */
+ if (*cdata) head->rte_name = xstrdup(cdata);
+ route_add_head(head);
+ break;
+
+ case 'T':
+ wpt = parse_trkpt(cdata);
+ if (wpt) track_add_wpt(head, wpt);
+ break;
+
+ case 'V':
+ if (strcmp(cin, G7T_HEADER) != 0) {
+ fatal(MYNAME ": Invalid version or invalid file!\n");
+ }
+ gardown = 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* --------------------------------------------------------------------------- */
+
+ff_vecs_t g7towin_vecs = {
+ ff_type_file,
+ { ff_cap_read, ff_cap_read, ff_cap_read },
+ rd_init,
+ NULL,
+ rd_deinit,
+ NULL,
+ data_read,
+ NULL,
+ NULL,
+ g7towin_args,
+ CET_CHARSET_MS_ANSI, 0
+};
+
+#endif /* CSVFMTS_ENABLED */